﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualBasic;
using MyWeb.Common.MemoryCache;
using MyWeb.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace MyWeb.Extensions.ServiceExtensions.Authorization
{
    /// <summary>
    /// JWTToken生成类
    /// </summary>
    public class JwtToken
    {
        private readonly ICaching _cache;
        private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
        //还是通过构造函数的方法，获取
        public JwtToken(ICaching cache,JwtSecurityTokenHandler jwtSecurityTokenHandler)
        {
            _cache = cache;
            _jwtSecurityTokenHandler = jwtSecurityTokenHandler;
    }

        /// <summary>
        /// 获取基于JWT的Token
        /// </summary>
        /// <param name="claims">需要在登陆的时候配置</param>
        /// <param name="permissionRequirement">在startup中定义的参数</param>
        /// <returns></returns>
        public TokenInfoViewModel BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement)
        {
            var now = DateTime.Now;
            // 实例化JwtSecurityToken
            var jwt = new JwtSecurityToken(
                issuer: permissionRequirement.Issuer,
                audience: permissionRequirement.Audience,
                claims: claims,
                notBefore: now,
                expires: now.AddMinutes(permissionRequirement.Expiration),
                signingCredentials: permissionRequirement.SigningCredentials
            );
            // 生成 Token
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
            _cache.Set("newjwttoken", encodedJwt, 30);
            //打包返回前台
            var ResponseJson = new TokenInfoViewModel
            {
                success = true,
                token = encodedJwt,
                expires_in = permissionRequirement.Expiration * 60,
                token_type = "Bearer"
            };
            return ResponseJson;
        }



        /// <summary>
        /// 生成身份信息
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="roleName">登录时的角色</param>
        /// <returns></returns>
        public Claim[] BuildClaims(string userName, List<string> roleName, PermissionRequirement _jwtConfig)
        {
            var now = DateTime.Now;
            // 配置用户标识
            var userClaims = new Claim[]
            {
                new Claim(ClaimTypes.Name,userName),
                new Claim(ClaimTypes.Role,string.Join(',', roleName)),
                new Claim(JwtRegisteredClaimNames.Iss,_jwtConfig.Issuer),//签发人
                new Claim(JwtRegisteredClaimNames.Aud,_jwtConfig.Audience),//受众
                new Claim(JwtRegisteredClaimNames.Nbf,now.ToString("yyyy-MM-dd HH:mm:ss ffffff")),//生效时间
                //new Claim(JwtRegisteredClaimNames.Iat,now.ToString("yyyy-MM-dd HH:mm:ss ffffff")),//签发时间
                new Claim(ClaimTypes.Expiration,_jwtConfig.Expiration.ToString()),//过期时间
                new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(now).ToUnixTimeSeconds().ToString())//签发时间
            };
            /*
             iss (issuer)：签发人
             exp (expiration time)：过期时间
             sub (subject)：主题
             aud (audience)：受众
             nbf (Not Before)：生效时间
             iat (Issued At)：签发时间
             jti (JWT ID)：编号
             */
            return userClaims;
        }


        /// <summary>
        /// 生成jwt令牌
        /// </summary>
        /// <param name="claims">自定义的claim</param>
        /// <returns></returns>
        public string BuildToken(Claim[] claims, PermissionRequirement _jwtConfig)
        {
            var creds = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConfig.SigningCredentials.ToString())), SecurityAlgorithms.HmacSha256);

            JwtSecurityToken tokenkey = new JwtSecurityToken(
                issuer: _jwtConfig.Issuer,
                audience: _jwtConfig.Audience,
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(_jwtConfig.Expiration),
                signingCredentials: creds);
            string tokenStr = "";
            try
            {
                tokenStr = new JwtSecurityTokenHandler().WriteToken(tokenkey);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            return tokenStr;
        }


        /// <summary>
        /// 从Token解密出JwtSecurityToken,JwtSecurityToken : SecurityToken
        /// </summary>
        /// <param name="tokenStr"></param>
        /// <returns></returns>
        public JwtSecurityToken GetJwtSecurityToken(string tokenStr)
        {
            string token = tokenStr.Replace($"{JwtBearerDefaults.AuthenticationScheme} ", string.Empty);
            var jwt = _jwtSecurityTokenHandler.ReadJwtToken(token);
            return jwt;
        }

        /// <summary>
        /// 从 Token 解密出SecurityToken
        /// </summary>
        /// <param name="tokenStr"></param>
        /// <returns></returns>
        public SecurityToken GetSecurityToken(string tokenStr)
        {
            string token = tokenStr.Replace("Bearer ", string.Empty);
            var jwt = _jwtSecurityTokenHandler.ReadToken(token);
            return jwt;
        }
    }
}
